﻿package com.myxh.genrator;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.TreeSet;

import com.myxh.compiler.FourElement;
import com.myxh.compiler.Word;
import com.myxh.compiler.WordType;

/**
 * 四元式到汇编代码生成器
 * 
 * 
 * @author HuangWeiCun
 * 
 */
public class Generater {

	/** 基本块集合 */
	TreeSet<BaseBlock> baseBlockSet = new TreeSet<BaseBlock>();

	/** 存放临时变量 */
	HashSet<String> tempVarSet = new HashSet<String>();

	/** 存放普通变量 */
	HashSet<String> varSet = new HashSet<String>();

	/** 四元式列表 */
	private List<FourElement> fourElemList = null;

	/** 单词表 */
	private List<Word> wordTable = null;

	/** 生成的汇编字符串 */
	StringBuilder stringBuilder = new StringBuilder();

	/** 换行符 */
	String newLine = System.getProperty("line.separator");

	public Generater(List<Word> wordTable, List<FourElement> fourElemList) {
		this.wordTable = wordTable;
		this.fourElemList = fourElemList;

		/** 预备工作：创建普通变量集合、临时变量集合、基本块序列 */
		setVarSet();
		setTempVarSet();
		setBlockSet();

	}

	public String assemblerString() throws IOException {

		// 生成代码

		stringBuilder.append(SegementUtil.getDatasSegement(varSet));
		stringBuilder.append(SegementUtil.getCodesSegement(baseBlockSet,
				tempVarSet, varSet));
		stringBuilder.append("END START");

		// 输出到文件中
		File file = new File("./masm532/");
		String path = file.getAbsolutePath();
		FileOutputStream fos = new FileOutputStream(path + "/abc.asm");
		OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
		osw.write(stringBuilder.toString());
		osw.close();
		System.out.println(stringBuilder.toString().length());

		return stringBuilder.toString();

	}

	/**
	 * 构造变量集合
	 */
	public void setVarSet() {

		for (Word word : wordTable) {
			if (word.type == WordType.IDENTIFIER) {
				varSet.add(word.wordStr);
			}
		}

	}

	public void setTempVarSet() {

		for (FourElement f : fourElemList) {

			if (f.op.equals("=") || f.op.equals("+") || f.op.equals("-")
					|| f.op.equals("*") || f.op.equals("/") || f.op.equals(">")
					|| f.op.equals("<")) {

				if (!varSet.contains(f.result)) {

					tempVarSet.add(f.result);
				}
			}
		}
	}

	/**
	 * 
	 * @return 基本块集合
	 */
	public void setBlockSet() {

		boolean isGoto = false;

		for (int i = 0; i < fourElemList.size(); i++) {
			FourElement fourElement = fourElemList.get(i);
			String op = fourElement.op;

			if (op.equals("RJ") || op.equals("FJ") || op.equals("TJ")) {

				int result = Integer.parseInt(fourElement.result);
				if (result == 1) {
					isGoto = true;
				}
				BaseBlock baseBlock = new BaseBlock(0, result, null, true);
				baseBlockSet.add(baseBlock);
				// 跳转语句下一条语句开始的基本块
				BaseBlock nextBaseBlock = new BaseBlock(0, fourElement.id + 1,
						null, false);
				baseBlockSet.add(nextBaseBlock);

			}

		}

		// 第一个基本块
		ArrayList<FourElement> partBaseBlockList0 = new ArrayList<FourElement>();
		partBaseBlockList0.add(fourElemList.get(0));
		BaseBlock baseBlock0 = new BaseBlock(0, 1, partBaseBlockList0, isGoto);
		baseBlockSet.add(baseBlock0);

		// 给基本块编号
		int num = 0;
		for (BaseBlock baseBlock : baseBlockSet) {
			baseBlock.id = num++;
		}

		// 把四元式加入到基本块中
		for (BaseBlock baseBlock : baseBlockSet) {
			int i = baseBlock.id;
			// 如果是最后一个基本块
			if (baseBlockSet.toArray().length - 1 == i) {
				ArrayList<FourElement> partBaseBlockList = new ArrayList<FourElement>();
				for (int j = baseBlock.importId; j < fourElemList.size() + 1; j++) {
					partBaseBlockList.add(fourElemList.get(j - 1));
					baseBlock.partBaseBlockList = partBaseBlockList;
				}
			} else {
				ArrayList<FourElement> partBaseBlockList = new ArrayList<FourElement>();
				for (int j = baseBlock.importId; j < ((BaseBlock) baseBlockSet
						.toArray()[i + 1]).importId; j++) {
					partBaseBlockList.add(fourElemList.get(j - 1));
					baseBlock.partBaseBlockList = partBaseBlockList;
				}
			}
		}

	}

}
